﻿using System.Collections.Generic;
using System.Reflection;
using JetBrains.Annotations;
using MugenMvvmToolkit.Interfaces;
using MugenMvvmToolkit.Ioc;
using MugenMvvmToolkit.Models;
using MugenMvvmToolkit.Utils;
using MugenMvvmToolkit.ViewModels;

namespace MugenMvvmToolkit.Infrastructure
{
    /// <summary>
    ///     Represents the class that is used to initialize the IOC adapter.
    /// </summary>
    public class InitializationStrategyExt : DefaultInitializationStrategy
    {
        #region Fields

        private readonly IList<IValidator> _validators;

        #endregion

        #region Constructors

        /// <summary>
        ///     Initializes a new instance of the <see cref="DefaultInitializationStrategy" /> class.
        /// </summary>
        public InitializationStrategyExt(IList<Assembly> viewAssemblies = null, IList<IValidator> validators = null)
            : base(viewAssemblies)
        {
            _validators = validators;
        }

        /// <summary>
        ///     Initializes a new instance of the <see cref="DefaultInitializationStrategy" /> class.
        /// </summary>
        public InitializationStrategyExt([NotNull]IViewModelSettings settings, IList<Assembly> viewAssemblies = null, IList<IValidator> validators = null)
            : base(settings, viewAssemblies)
        {
            _validators = validators;
        }

        #endregion

        #region Overrides of DefaultInitializationStrategy

        /// <summary>
        ///     Initializes the specified <see cref="IIocAdapter" />.
        /// </summary>
        public override void Initialize(IIocAdapter iocAdapter)
        {
            base.Initialize(iocAdapter);
#if WPF
            IocAdapter.BindToBindingInfo<IViewPageMappingProvider>(GetViewPageMappingProvider);
#endif
            IocAdapter.BindToBindingInfo<IEntityStateProvider>(GetEntityStateProvider);
            IocAdapter.BindToBindingInfo<IValidationProvider>(GetValidationProvider);
            IocAdapter.BindToBindingInfo<IValidatorProvider>(GetValidatorProvider);
            if (!IocAdapter.CanResolve(typeof(IValidatorProvider))) return;
            var validatorProvider = IocAdapter.Get<IValidatorProvider>();
            foreach (var validator in GetValidators())
            {
                validatorProvider.Register(validator);
            }
        }


#if WPF
        /// <summary>
        ///     Gets the <see cref="IViewManager" /> which will be used in all view models by default.
        /// </summary>
        /// <returns>An instance of <see cref="IViewManager" />.</returns>
        protected override BindingInfo<IViewManager> GetViewManager()
        {
            return
                BindingInfo<IViewManager>.FromInstance(new ViewManager(MvvmUtilsInternalAdvanced.CanInitializeView,
                    IocAdapter.Get<IViewMappingProvider>()));
        }
#endif

#if !NOANNOTATIONVALIDATION
        /// <summary>
        /// Gets the <see cref="IDisplayNameProvider"/> which will be used by default.
        /// </summary>
        /// <returns>An instance of <see cref="IDisplayNameProvider"/>.</returns>
        protected override BindingInfo<IDisplayNameProvider> GetDisplayNameProvider()
        {
            return BindingInfo<IDisplayNameProvider>.FromInstance(new AnnotationDisplayNameProvider());
        }
#endif

        #endregion

        #region Methods

        /// <summary>
        /// Gets the <see cref="IValidationProvider"/> which will be used by default.
        /// </summary>
        /// <returns>An instance of <see cref="IValidationProvider"/>.</returns>
        protected virtual BindingInfo<IValidationProvider> GetValidationProvider()
        {
#if !NOANNOTATIONVALIDATION
            return BindingInfo<IValidationProvider>.FromInstance(new DataAnnotationValidationProvider(IocAdapter.Get<IDisplayNameProvider>(), IocAdapter));
#else
            return BindingInfo<IValidationProvider>.Empty;
#endif
        }

        /// <summary>
        /// Gets validators.
        /// </summary>
        /// <returns>A series of instances of <see cref="IValidator"/>.</returns>
        protected virtual IList<IValidator> GetValidators()
        {
            if (_validators != null)
                return _validators;
#if !NOANNOTATIONVALIDATION
            return new IValidator[] { new ValidationProviderValidator(), new ValidatableViewModelValidator() };
#else
            return new IValidator[] { new ValidatableViewModelValidator() };
#endif
        }

        /// <summary>
        /// Gets the <see cref="IEntityStateProvider"/> which will be used by default.
        /// </summary>
        /// <returns>An instance of <see cref="IEntityStateProvider"/>.</returns>
        protected virtual BindingInfo<IEntityStateProvider> GetEntityStateProvider()
        {
            return BindingInfo<IEntityStateProvider>.FromType<EntityStateProvider>(
                    DependencyLifecycle.TransientScopeInstance);
        }

        /// <summary>
        /// Gets the <see cref="IValidatorProvider"/> which will be used by default.
        /// </summary>
        /// <returns>An instance of <see cref="IValidatorProvider"/>.</returns>
        protected virtual BindingInfo<IValidatorProvider> GetValidatorProvider()
        {
            return BindingInfo<IValidatorProvider>.FromInstance(new ValidatorProvider(IocAdapter));
        }

#if WPF
        /// <summary>
        /// Gets the <see cref="IViewPageMappingProvider"/> which will be used by default.
        /// </summary>
        /// <returns>An instance of <see cref="IViewPageMappingProvider"/>.</returns>
        protected virtual BindingInfo<IViewPageMappingProvider> GetViewPageMappingProvider()
        {
            return BindingInfo<IViewPageMappingProvider>.FromInstance(new AttributeViewPageMappingProvider(GetViewAssemblies()));
        }
#endif
        #endregion
    }
}
